﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Services;
using A2DFramework.AOPService.Core;

namespace A2DFramework.AOPService
{
    public abstract class BaseAOPRealProxy : RealProxy
    {
        private MarshalByRefObject target;
        private List<IAOPProcessor> aopProcessors = new List<IAOPProcessor>();

        public BaseAOPRealProxy(Type objType, MarshalByRefObject obj)
            : base(objType)
        {
            target = obj;
            aopProcessors=GetAOPProcessors();
        }

        protected abstract List<IAOPProcessor> GetAOPProcessors();

        public override IMessage Invoke(IMessage msg)
        {
            IMessage retMsg = null;
            IMethodCallMessage methodCall = (IMethodCallMessage)msg;
            IMethodReturnMessage methodReturn = null;
            object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[];
            methodCall.Args.CopyTo(copiedArgs, 0);
            if (msg is IConstructionCallMessage)
            {

                IConstructionCallMessage ccm = (IConstructionCallMessage)msg;
                RemotingServices.GetRealProxy(target).InitializeServerObject(ccm);
                ObjRef oRef = RemotingServices.Marshal(target);
                RemotingServices.Unmarshal(oRef);
                retMsg = EnterpriseServicesHelper.CreateConstructionReturnMessage(ccm, (MarshalByRefObject)this.GetTransparentProxy());

            }
            else
            {
                object returnValue = null;

                #region PreProcess
                FollowAction follow=new FollowAction(true);
                for (int i = 0; i < aopProcessors.Count; i++)
                {
                    IAOPProcessor processor = aopProcessors[i];
                    follow = processor.PreProcess(msg);
                    if (follow.StopExecute)
                    {
                        returnValue = follow.Result;
                        break;
                    }
                }
                #endregion

                #region Method Invoke
                try
                {   
                    if (!follow.StopExecute)
                        returnValue = methodCall.MethodBase.Invoke(this.target, copiedArgs);
                    methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
                }
                catch (Exception ex)
                {
                    if (null != ex.InnerException)
                    {
                        methodReturn = new ReturnMessage(ex.InnerException, methodCall);
                    }
                    else
                    {
                        methodReturn = new ReturnMessage(ex, methodCall);
                    }
                }
                retMsg = methodReturn;
                #endregion

                #region PostProcess
                if (!follow.StopExecute)
                {
                    for (int i = aopProcessors.Count - 1; i >= 0; i--)
                    {
                        IAOPProcessor processor = aopProcessors[i];
                        processor.PostProcess(msg, methodReturn);
                    }
                }
                #endregion
            }
            return retMsg;
        }
    }
}
